package org.infodavid.common.messaging;

import java.nio.charset.Charset;

import javax.ejb.MessageDrivenContext;
import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.transaction.UserTransaction;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.jms.message.MessageProxy;

import org.infodavid.common.lang.Serializer;
import org.infodavid.common.naming.NamingUtil;

/**
 * The Class MessagingUtil.
 */
public final class MessagingUtil {

  /** The Constant LOGGER. */
  private static final Log LOGGER = LogFactory.getLog(MessagingUtil.class);

  /**
   * No instance for this utilities class.
   */
  private MessagingUtil() {
    super();
  }

  /**
   * Ger retry count.
   * @param msg the JMS message
   * @return the count or -1 if it cannot be retrieved
   */
  public static int getDeliveryCount(final Message msg) {
    int count = -1;

    if (msg instanceof MessageProxy) {
      count = ((MessageProxy)msg).getDeliveryCount();
    }

    return count;
  }

  /**
   * Rollback.
   * @param context the MDB context
   */
  public static void rollback(final MessageDrivenContext context) {
    try {
      if (context == null) {
        final Object obj =
            NamingUtil.getContext().lookup(NamingUtil.USER_TRANSACTION_JNDI_NAME);

        if (obj instanceof UserTransaction) {
          ((UserTransaction)obj).setRollbackOnly();
        }

        LOGGER.debug("Rollback invoked directly on the UserTransaction");
        LOGGER
            .info("Message will be processed again later if max number of retries is not reached");
      }
      else {
        context.setRollbackOnly();

        LOGGER
            .info("Message will be processed again later if max number of retries is not reached");
      }
    }
    catch (final Exception e2) {
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("An error occurs while rolling back the MDB context", e2);
      }
    }
  }

  /**
   * Is the expected object message.
   * @param msg the JMS message
   * @param expected the expected class of the embedded object
   */
  @SuppressWarnings("rawtypes")
  public static boolean isObjectMessage(final Message msg, final Class expected) {
    boolean result = false;

    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug("Message: " + Serializer.getInstance().serialize(msg, Charset.defaultCharset()));

    }

    if (msg instanceof ObjectMessage) {
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("The type of message is: object message");
      }

      final ObjectMessage objectMessage = (ObjectMessage)msg;
      Object object;

      try {
        object = objectMessage.getObject();
      }
      catch (final Exception e) {
        LOGGER.error("Error while retrieving the data of the message ", e);

        object = null;
      }

      if (object == null) {
        LOGGER.warn("Object is null");
      }
      else if (expected.isInstance(object)) {
        final int deliveryCount = getDeliveryCount(msg);

        if (deliveryCount > 1) {
          LOGGER.info("Message delivery count: " + deliveryCount);
        }

        result = true;
      }
      else {
        LOGGER.warn("This object is not supported: " + object.getClass());
      }
    }
    else {
      LOGGER.error("The message type is not supported: " + msg);
    }

    return result;
  }
}
